﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using GraphSharp;
using QuickGraph;
using QuickGraph.Algorithms;
using GraphSharp.Contracts;
using GraphSharp.Controls;
using Microsoft.Contracts;
using UMO.UmoControls;
namespace UMO
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private static readonly string SEARCH_PANEL_KEY = "SEARCH_PANEL";
        private static readonly string EVENT_PANEL_KEY = "EVENT_PANEL";
        private static readonly string TREE_VIEW_KEY = "TREE_VIEW_PANEL";
        private static readonly string POINTS_PANEL_KEY = "POINTS_PANEL";
        private static readonly string NAV_PANEL_KEY = "NAV_PANEL";
        public Dictionary<int, UmoNode> GraphNodes = new Dictionary<int, UmoNode>();
        private UmoNavigation canvasNavigation;
        public Dictionary<string, UmoPanel> WindowPanels = new Dictionary<string, UmoPanel>();
        public MainWindow()
        {
            this.GraphNodes.Add(1,new UmoNode(UmoNodeType.start,"start",1,0,0));
            this.GraphNodes.Add(2, new UmoNode(UmoNodeType.folder, "new folder2", 2, 1, 0));
            this.GraphNodes.Add(3, new UmoNode(UmoNodeType.folder, "new folder3", 3, 1, 0));
            UpdateGraph();
            InitializeComponent();
            UserControl searchBar = UmoPanel.ReturnAlignedUserControl(new UmoSearch(), "SEARCH_BAR", new Thickness(0, 0, 0, 0), HorizontalAlignment.Stretch, VerticalAlignment.Top);
            UserControl listBoxControl = UmoPanel.ReturnAlignedUserControl(new UmoList(), "POINTS_LIST", new Thickness(0, 0, 0, 0));
            UserControl treeView = UmoPanel.ReturnAlignedUserControl(new UmoNodesTreeView(this), "TREE_VIEW", new Thickness(0, 0, 0, 0));
            UserControl eventsListBoxControl = UmoPanel.ReturnAlignedUserControl(new UmoList(), "EVENTS_LIST", new Thickness(0, 0, 0, 0));
            UserControl navigationControl = UmoPanel.ReturnAlignedUserControl(new UmoNavigation(this), "NAVIGATION_MAP", new Thickness(0, 0, 0, 0));
            //
            UmoPanel searchPanel = new UmoPanel(SEARCH_PANEL_KEY, searchBar, new Thickness(5, 0, 5, 5), HorizontalAlignment.Stretch, VerticalAlignment.Bottom, 0, 85);
            UmoPanel eventListPanel = new UmoPanel(EVENT_PANEL_KEY, eventsListBoxControl, new Thickness(0, 5, 5, 94), HorizontalAlignment.Right, VerticalAlignment.Stretch, 200, 0, "събития");
            UmoPanel treeViewPanel = new UmoPanel(TREE_VIEW_KEY, treeView, new Thickness(5, 5, 0, 279), HorizontalAlignment.Left, VerticalAlignment.Stretch, 200, 0, "структура на схемата");
            UmoPanel pointsListPanel = new UmoPanel(POINTS_PANEL_KEY, listBoxControl, new Thickness(5, 0, 0, 125), HorizontalAlignment.Left, VerticalAlignment.Bottom, 200, 150, "отбелязани точки");
            UmoPanel navigationPanel = new UmoPanel(NAV_PANEL_KEY, navigationControl, new Thickness(5, 136, 0, 66), HorizontalAlignment.Left, VerticalAlignment.Bottom, 200, 55, "увеличение на схемата");
            WindowPanels.Add(SEARCH_PANEL_KEY, searchPanel);
            WindowPanels.Add(EVENT_PANEL_KEY, eventListPanel);
            WindowPanels.Add(TREE_VIEW_KEY, treeViewPanel);
            WindowPanels.Add(POINTS_PANEL_KEY, pointsListPanel);
            WindowPanels.Add(NAV_PANEL_KEY, navigationPanel);
            foreach (UmoPanel panel in WindowPanels.Values)
            {
                this.MainGrid.Children.Add(panel);
            }
            this.canvasNavigation = (UmoNavigation)this.WindowPanels[NAV_PANEL_KEY].PanelContainerGrid.Children[0];
            //this.canvasNavigation.SetParentWindow(this);            
        }

        private void SetGraphLayoutMargins()
        {
            double margin = 100;
            double marginMultiplier = 2;
            double Margin = margin * marginMultiplier;
            this.graphLayout.Margin = new Thickness(Margin);
        }
        private IBidirectionalGraph<object, IEdge<object>> _graph;
        public static void alert(string message)
        {
            MessageBox.Show(message);
        }
        public IBidirectionalGraph<object, IEdge<object>> GraphToV
        {
            get
            {
                return this._graph;
            }
        }
        public static readonly string CONFIRMATION_DEFAULT_CAPTION = "Потвърждение";
        public static readonly string CONFIRM_CLOSE_DEFAULT_MESSAGE = "Сигурни ли сте че искате да прекратите?";
        public static bool ConfirmAction(string message, string caption)
        {
            bool valueToRet = false;
            if (MessageBox.Show(message, caption,MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                valueToRet = true;
            }
            return valueToRet;
        }
        private static Exception INCORRECT_NODE_REFFERANCE = new Exception("Настъпи грешка при опресняването на схемата. Вероятна причина е грешно индексиране на точките.");
        public void UpdateGraph(bool reload=false)
        {
            var g = new BidirectionalGraph<object, IEdge<object>>();
            Dictionary<int, UmoTreeNode> NodesToDraw = new Dictionary<int, UmoTreeNode>();
            foreach (UmoNode uNode in this.GraphNodes.Values)
            {
                UmoTreeNode nodeToAdd=new UmoTreeNode(uNode.Index,uNode.ParentIndex);
                NodesToDraw.Add(uNode.Index, nodeToAdd);
            }
            foreach (UmoTreeNode node in NodesToDraw.Values)
            {
                g.AddVertex(node);
                if (NodesToDraw.ContainsKey(node._referance) == true && NodesToDraw.ContainsKey(node._index) == true)
                {
                    g.AddEdge(new Edge<object>(NodesToDraw[node._referance], NodesToDraw[node._index]));
                }
                else if (node._referance != 0)
                {
                    throw INCORRECT_NODE_REFFERANCE;
                }
            }
            this._graph = g;
            if (reload == true)
            {
                ReloadGraph();
            }
        }
        private void ReloadGraph()
        {
            this.graphLayout.Graph = this.GraphToV;

        }
        
        private Point? initDragPoint;
        private Point? lastMousePositionOnTarget;
        public Point? lastCenterPositionOnTarget;

        private void TrackScrollViewer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Point mousePos = e.GetPosition(this.TrackScrollViewer);
            if (mousePos.X <= this.TrackScrollViewer.ViewportWidth && mousePos.Y <
                this.TrackScrollViewer.ViewportHeight)
            {
                this.TrackScrollViewer.Cursor = Cursors.SizeAll;
                initDragPoint = mousePos;
                Mouse.Capture(this.TrackScrollViewer);
            }
        }

        private void TrackScrollViewer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            this.TrackScrollViewer.Cursor = Cursors.Arrow;
            this.TrackScrollViewer.ReleaseMouseCapture();
            initDragPoint = null;
        }
        private bool AreCanvasMarginsUpdated;
        private void TrackScrollViewer_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.AreCanvasMarginsUpdated == false)
            {
                SetGraphLayoutMargins();
                this.AreCanvasMarginsUpdated = true;
            }
            if (initDragPoint.HasValue)
            {
                Point posNow = e.GetPosition(this.TrackScrollViewer);

                double dX = posNow.X - initDragPoint.Value.X;
                double dY = posNow.Y - initDragPoint.Value.Y;

                initDragPoint = posNow;

                this.TrackScrollViewer.ScrollToHorizontalOffset(this.TrackScrollViewer.HorizontalOffset - dX);
                this.TrackScrollViewer.ScrollToVerticalOffset(this.TrackScrollViewer.VerticalOffset - dY);
            }
        }

        private void TrackScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            lastMousePositionOnTarget = Mouse.GetPosition(this.TrackScrollViewer);
            float zoomChange = 0.1F;
            if (e.Delta > 0)
            {
                this.canvasNavigation.ZoomSlider.Value += zoomChange;
            }
            if (e.Delta < 0)
            {
                this.canvasNavigation.ZoomSlider.Value -= zoomChange;
            }

            e.Handled = true;
        }

        private void TrackScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.ExtentHeightChange != 0 || e.ExtentWidthChange != 0)
            {
                Point? targetBefore = null;
                Point? targetNow = null;

                if (!lastMousePositionOnTarget.HasValue)
                {
                    if (lastCenterPositionOnTarget.HasValue)
                    {
                        var centerOfViewport = new Point(TrackScrollViewer.ViewportWidth / 2,
                                                         TrackScrollViewer.ViewportHeight / 2);
                        Point centerOfTargetNow =
                              TrackScrollViewer.TranslatePoint(centerOfViewport, this.MainGrid);

                        targetBefore = lastCenterPositionOnTarget;
                        targetNow = centerOfTargetNow;
                    }
                }
                else
                {
                    targetBefore = lastMousePositionOnTarget;
                    targetNow = Mouse.GetPosition(this.MainGrid);

                    lastMousePositionOnTarget = null;
                }

                if (targetBefore.HasValue)
                {
                    double dXInTargetPixels = targetNow.Value.X - targetBefore.Value.X;
                    double dYInTargetPixels = targetNow.Value.Y - targetBefore.Value.Y;

                    double multiplicatorX = e.ExtentWidth / this.MainGrid.Width;
                    double multiplicatorY = e.ExtentHeight / this.MainGrid.Height;

                    double newOffsetX = TrackScrollViewer.HorizontalOffset -
                                        dXInTargetPixels * multiplicatorX;
                    double newOffsetY = TrackScrollViewer.VerticalOffset -
                                        dYInTargetPixels * multiplicatorY;

                    if (double.IsNaN(newOffsetX) || double.IsNaN(newOffsetY))
                    {
                        return;
                    }

                    TrackScrollViewer.ScrollToHorizontalOffset(newOffsetX);
                    TrackScrollViewer.ScrollToVerticalOffset(newOffsetY);
                }
            }
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {

        }

        private void exitApp_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }


    }
}
